const fs = require('fs')
const pathNode = require('path')
const EPub = require('../utils/epub')
const xml2js = require('xml2js').parseString
const admZip = require('adm-zip')
const { MIME_TYPE_EPUB, UPLOAD_URL, UPLOAD_PATH,OLD_UPLOAD_URL} = require('../utils/constant')
class Book {
    constructor(file, data) {
        if (file) {
            this.createBookFromFile(file)
        } else {
            this.createBookFromData(data)
        }
    }
    createBookFromFile(file) {
        const { originalname, mimetype = MIME_TYPE_EPUB, destination, filename, path } = file
        const suffix = mimetype === MIME_TYPE_EPUB ? '.epub' : ''
        const oldPath = path
        const bookPath = `${destination}/book/${filename}${suffix}`
        const url = `${UPLOAD_URL}/book/${filename}${suffix}`
        const unzipPath = `${UPLOAD_PATH}/unzip/${filename}`
        const unzipUrl = `${UPLOAD_URL}/unzip/${filename}`
        if (!fs.existsSync(unzipPath)) {
            fs.mkdirSync(unzipPath, { recursive: true })
        }
        if (fs.existsSync(oldPath) && !fs.existsSync(bookPath)) {
            fs.renameSync(oldPath, bookPath)
        }
        this.fileName = filename  //文件名
        this.path = `/book/${filename}${suffix}`  //epub 电子书路径
        this.filePath = this.path                 //epub 电子书路径
        this.url = url                            //epub 文件url
        this.title = '' // 标题
        this.author = '' // 作者
        this.publisher = '' // 出版社
        this.contents = [] // 目录
        this.cover = '' // 封面图片URL
        this.category = -1 // 分类ID
        this.categoryText = '' // 分类名称
        this.language = '' // 语种
        this.unzipPath = `/unzip/${filename}` // 解压后的电子书目录
        this.unzipUrl = unzipUrl // 解压后的电子书链接
        this.originalName = originalname
    }
    createBookFromData(data) {
        this.fileName = data.fileName
        this.cover = data.cover
        this.title = data.title
        this.author = data.author
        this.publisher = data.publisher
        this.bookId = data.fileName
        this.language = data.language
        this.rootFile = data.rootFile
        this.originalName = data.originalName
        this.path = data.path || data.filePath
        this.filePath = data.path || data.filePath
        this.unzipPath = data.unzipPath
        this.coverPath = data.coverPath
        this.createUser = data.username
        this.createDt = new Date().getTime()
        this.updateDt = new Date().getTime()
        this.updateType = data.updateType === 0 ? data.updateType : 1
        this.contents = data.contents || []
    }


    getContents(){
        return this.contents
    }

    reset(){
        if(Book.pathExists(this.filePath)){
            fs.unlinkSync(Book.genPath(this.filePath))
        }
        if(Book.pathExists(this.coverPath)){
            fs.unlinkSync(this.coverPath)
        }
        if(Book.pathExists(this.unzipPath)){
            // 删除解压目录，windows下无效
            // fs.rmdirSync(Book.genPath(this.unzipPath),{recursive:true})
        }
    }

    toDb(){
        return {
            fileName: this.fileName,
            cover: this.cover,
            title: this.title,
            author: this.author,
            publisher: this.publisher,
            bookId: this.bookId,
            updateType: this.updateType,
            language: this.language,
            rootFile: this.rootFile,
            originalName: this.originalName,
            filePath: this.path,
            unzipPath: this.unzipPath,
            coverPath: this.coverPath,
            createUser: this.createUser,
            createDt: this.createDt,
            updateDt: this.updateDt,
            category: this.category || 99,
            categoryText: this.categoryText || '自定义'
        }
    }

    parse() {
        return new Promise((resolve, reject) => {
            const bookPath = `${UPLOAD_PATH}${this.path}`
            if (fs.existsSync(bookPath)) {
                const epub = new EPub(bookPath)
                epub.parse()

                epub.on('error', function (err) {
                    reject(err)
                })
                epub.on('end', err => {
                    if (err) {
                        reject(err)
                    } else {
                        const { creator, creatorFileAs, description, publisher, title, language, cover } = epub.metadata
                        if (!title) {
                            reject(new Error('标题不存在'))
                        } else {
                            this.title = title
                            this.author = creator || creatorFileAs || 'unknow'
                            this.publisher = publisher || 'unknow'
                            this.rootFile = epub.rootFile
                            this.language = language || 'en'

                            const callback = (error, imgBuffer, mimeType) => {
                                var suffix = mimeType.split('/')[1]
                                var coverPath = `${UPLOAD_PATH}/img/${this.fileName}.${suffix}`
                                var coverUrl = `${UPLOAD_URL}/img/${this.fileName}.${suffix}`
                                if (error) {
                                    reject(new Error('读取不到封面图'))
                                } else {
                                    fs.writeFileSync(coverPath, imgBuffer, 'binary')
                                    this.cover = coverUrl
                                    this.coverPath = coverPath.replace(UPLOAD_PATH,'')
                                    resolve(this)
                                }

                            }
                            
                            try {
                                this.unzip() //解压电子书
                                this.parseContents(epub).then(({chapters,contentsTree})=>{
                                    this.contents = chapters
                                    this.contentsTree = contentsTree
                                })

                                epub.getImage(cover, callback)
                                
                            } catch (e) {
                                reject(e)
                            }
                            

                        }

                    }
                })
            } else {
                reject(new Error('文件不存在'))
            }

        })

    }

    unzip() {
        var zip = new admZip(Book.genPath(this.path))
        zip.extractAllTo(Book.genPath(this.unzipPath), true)
    }
    parseContents(epub) {
        function getNcxFilePath() {
            const manifest = epub && epub.manifest
            const spine = epub && epub.spine
            const toc = spine && spine.toc
            const ncx = manifest && manifest.ncx

            return (ncx && ncx.href) || (toc && toc.href)
        }
        function findParent(array,level=0,pid='') {
            return array.map(item=>{
                item.level = level
                item.pid = pid
                if(item.navPoint&&item.navPoint.length>0){
                    //进行递归循环
                    findParent(item.navPoint,level+1,item['$'].id)
                }else if(item.navPoint){
                    item.navPoint.level = level+1
                    item.navPoint.pid = item['$'].id
                }
                return item
            })
        }
        function flatten(array) {
            return [].concat(...array.map(item => {
                if(item.navPoint&&item.navPoint.length>0){
                    return [].concat(item,...flatten(item.navPoint))
                }else if(item.navPoint){
                    return [].concat(item,item.navPoint)
                }else{
                    return item
                }
                
            }))
        }
        const ncxFilePath = Book.genPath(`${this.unzipPath}/${getNcxFilePath()}`)
        if (fs.existsSync(ncxFilePath)) {
            const fileName = this.fileName
            const unzipPath = this.unzipPath
            return new Promise((resolve, reject) => {

                const xml = fs.readFileSync(ncxFilePath, 'utf-8')
                const dir = pathNode.dirname(ncxFilePath).replace(UPLOAD_PATH,'')
                //将xml 文件转为json
                xml2js(xml, { explicitArray: false, ignoreAttrs: false }, function (err, json) {
                    if (!err) {
                        const navMap = json.ncx.navMap
                        if (navMap.navPoint) {
                            navMap.navPoint = findParent(navMap.navPoint)
                            const newNavMap = flatten(navMap.navPoint) // 将目录拆分为扁平结构
                            const chapters = []
                            newNavMap.forEach((chapter, index) => {
                                const src = chapter.content['$'].src
                                chapter.id = src
                                chapter.href = `${dir}${src}`.replace(unzipPath,'')
                                chapter.text = `${UPLOAD_URL}${dir}/${src}`
                                chapter.label = chapter.navLabel.text || ''                                
                                chapter.navId = chapter['$'].id
                                chapter.fileName = fileName
                                chapter.order = index + 1
                                chapters.push(chapter)
                            })
                            const contentsTree = Book.genContentsTree(chapters)

                            resolve({chapters,contentsTree})
                            // console.log(epub.flow)
                        }else{
                            reject(new Error('电子书目录有问题'))
                        }
                    }
                    //    console.log(JSON.stringify(json.ncx.navMap))
                })
            })
        } else {
            throw new Error('电子书目录获取不到')
        }


    }
    static genPath(path) {
        if (!path.startsWith('/')) {
            return `/${path}`
        } else {
            return `${UPLOAD_PATH}${path}`
        }
    }
    static genCoverUrl(book){
        const {cover} = book
        if(+book.updateType ===0){
            
            if(cover){
                if(cover.startsWith('/')){
                    return `${OLD_UPLOAD_URL}${cover}`
                }else{
                    return `${OLD_UPLOAD_URL}/${cover}`
                }
            }else{
                return null
            }
        }else{
            return book.cover
        }
        
    }

    static genContentsTree(contents){
        if(contents){
            const contentsTree = []
            contents.forEach(c=>{
                c.children = []
                if(c.pid===""){
                    contentsTree.push(c)
                }else{
                    const parent = contents.find(_=>_.navId===c.pid)
                    parent.children.push(c)
                }
            })
            return contentsTree
        }
    }
    static pathExists(path){
        if(path.startsWith(UPLOAD_PATH)){
            return fs.existsSync(path)
        }else{
            return fs.existsSync(Book.genPath(path))
        }
    }
}

module.exports = Book